﻿using System;
using System.Formats.Asn1;
using System.IO;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;

namespace Email
{
    public class Pop3
    {
        private string Server = "pop.qq.com";
        private int Port = 995; // SSL默认端口
        private string Username;
        private string Password;

        private TcpClient client;
        private SslStream sslStream;
        private StreamReader reader;
        private StreamWriter writer;

        public Pop3(string Username, string Password)
        {
            this.Username = Username;
            this.Password = Password;
        }
        // 建立连接
        public void Connect()
        {
            try
            {
                client = new TcpClient(Server, Port);
                sslStream = new SslStream(client.GetStream());
                sslStream.AuthenticateAsClient(Server);

                reader = new StreamReader(sslStream, Encoding.ASCII);
                writer = new StreamWriter(sslStream, Encoding.ASCII) { AutoFlush = true };

                // 读取服务器欢迎消息
                Console.WriteLine(reader.ReadLine());

                // 发送USER命令
                SendCommand($"USER {Username}");
                Console.WriteLine(reader.ReadLine());

                // 发送PASS命令
                SendCommand($"PASS {Password}");
                Console.WriteLine(reader.ReadLine());

                Console.WriteLine("连接成功并验证通过");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"连接失败: {ex.Message}");
            }
        }
        // List指令实现
        public void List()
        {
            try
            {
                // 发送LIST命令
                SendCommand("LIST");
                string response = reader.ReadLine();
                Console.WriteLine(response);

                // 检查服务器响应
                if (!response.StartsWith("+OK"))
                {
                    throw new Exception("服务器响应失败");
                }

                // 读取邮件列表
                string line;
                while ((line = reader.ReadLine()) != ".")
                {
                    Console.WriteLine(line);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"获取邮件列表失败: {ex.Message}");
            }
        }
        // 打开邮件
        public void Open(int messageNumber)
        {
            try
            {
                if (writer == null || reader == null)
                {
                    throw new InvalidOperationException("连接尚未建立。请先调用Connect方法。");
                }

                // 发送RETR命令
                SendCommand($"RETR {messageNumber}");
                string response = reader.ReadLine();
                Console.WriteLine(response);

                // 检查服务器响应
                if (!response.StartsWith("+OK"))
                {
                    throw new Exception("服务器响应失败");
                }

                // 读取邮件内容
                StringBuilder emailContent = new StringBuilder();
                string line;
                while ((line = reader.ReadLine()) != ".")
                {
                    emailContent.AppendLine(line);
                }

                Console.WriteLine(emailContent.ToString());

                // 输出邮件内容
                Console.WriteLine("邮件头:");
                GetHeadInfo(emailContent.ToString());   // 给出头部重要信息
                string boundary = GetBoundary(emailContent.ToString()); // 找到块边界符

                Console.WriteLine("邮件体:");
                foreach(string str in GetBodyInfo(emailContent.ToString(), "--" + boundary)){
                   // Console.WriteLine(str);
                    Console.WriteLine(DecodeBase64(str));
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"获取邮件内容失败: {ex.Message}");
            }
        }

        public void Delete(int emailIndex)
        {
            SendCommand($"DELE {emailIndex}");
            string response = reader.ReadLine();

            if (!response.StartsWith("+OK"))
            {
                throw new InvalidOperationException($"Error deleting email at index {emailIndex}: {response}");
            }
        }

        // 释放连接
        public void Disconnect()
        {
            if (writer != null)
            {
                SendCommand("QUIT");
                Console.WriteLine(reader.ReadLine());
            }

            reader?.Close();
            writer?.Close();
            sslStream?.Close();
            client?.Close();
        }

        private void SendCommand(string command)
        {
            writer.WriteLine(command);
            writer.Flush();
        }
        // 解码提取后的base64
        private static string DecodeBase64(string base64EncodedData)
        {
            try{
                // 将 Base64 编码的字符串转换为字节数组
                byte[] base64EncodedBytes = Convert.FromBase64String(base64EncodedData);
                
                // 将字节数组解码为字符串
                return Encoding.UTF8.GetString(base64EncodedBytes);
            }

            catch (FormatException e)
            {
                Console.WriteLine($"Invalid Base64 string: {e.Message}");
                return null;
            }
        }
        // 解码Header的Base64，因为存在混合情况
        private static string DecodeBase64String(string input)
        {
            // 正则表达式匹配Base64编码的内容
            string pattern = @"=\?utf-8\?B\?(.*?)\?=";
            return Regex.Replace(input, pattern, match =>
            {
                string base64Content = match.Groups[1].Value;
                byte[] data = Convert.FromBase64String(base64Content);
                return Encoding.UTF8.GetString(data);
            });
        }
        // 获取头部信息
        private static void GetHeadInfo(string emailContent)
        {
            string from = ExtractHeaderField(emailContent, "From");
            string to = ExtractHeaderField(emailContent, "To");
            string subject = ExtractHeaderField(emailContent, "Subject");
            string Date = ExtractHeaderField(emailContent, "Date");
            // 确定解码方式
            from = DetermineEncoding(from) ? DecodeBase64String(from): DecodeQuotedPrintable(from);
            to = DetermineEncoding(to) ? DecodeBase64String(to): DecodeQuotedPrintable(to);
            subject =  DetermineEncoding(subject) ? DecodeBase64String(subject): DecodeQuotedPrintable(subject);

            Console.WriteLine($"From: {from}");
            Console.WriteLine($"To: {to}");
            Console.WriteLine($"Subject: {subject}");
            Console.WriteLine($"Date: {Date}");
        }
        // 提取头部重要字段
        private static string ExtractHeaderField(string emailContent, string fieldName)
        {
            // Pattern to match both Base64 encoded and plain text content
            string pattern = $@"^{fieldName}:\s*(=\?utf-8\?B\?(.*?)\?=|.*)";
            Match match = Regex.Match(emailContent, pattern, RegexOptions.Multiline | RegexOptions.IgnoreCase);

            if (match.Success)
            {
                string fieldValue = match.Groups[2].Success ? match.Groups[2].Value : match.Groups[1].Value;
                return match.Groups[2].Success ? DecodeBase64(fieldValue) : fieldValue.Trim();
            }

            return string.Empty;
        }
        // 提取正文base64编码字符串
        private static List<string> GetBodyInfo(string input, string endString)
        {
            List<string> results = new List<string>();
            string pattern = $@"Content-Transfer-Encoding: base64\s*(.*?)(?:{Regex.Escape(endString)}|\r?\n\r?\n|$)";
            MatchCollection matches = Regex.Matches(input, pattern, RegexOptions.Singleline);

            foreach (Match match in matches)
            {
                if (match.Groups.Count > 1)
                {
                    results.Add(match.Groups[1].Value.Trim());
                }
            }

            return results;
        }
        // 解码quoted-printable
        private static string DecodeQuotedPrintable(string input)
        {
            // Remove the prefix and suffix
            string pattern = @"=\?utf-8\?Q\?(.*?)\?=";
            Match match = Regex.Match(input, pattern);
            if (!match.Success)
            {
                throw new ArgumentException("Input is not in the Quoted-Printable format.");
            }

            string encodedText = match.Groups[1].Value;

            // Decode the quoted-printable part
            byte[] bytes = new byte[encodedText.Length];
            int byteIndex = 0;

            for (int i = 0; i < encodedText.Length; i++)
            {
                if (encodedText[i] == '=' && i + 2 < encodedText.Length)
                {
                    string hex = encodedText.Substring(i + 1, 2);
                    bytes[byteIndex++] = Convert.ToByte(hex, 16);
                    i += 2;
                }
                else
                {
                    bytes[byteIndex++] = (byte)encodedText[i];
                }
            }

            return Encoding.UTF8.GetString(bytes, 0, byteIndex);
        }
        // 寻找正文定界符
        private static string GetBoundary(string input)
        {
            string pattern = @"boundary=""([^""]*)""";
            Match match = Regex.Match(input, pattern);

            if (match.Success && match.Groups.Count > 1)
            {
                return match.Groups[1].Value;
            }

            return string.Empty;
        }
        // base64 or quoted-printable
        private static bool DetermineEncoding(string input)
        {
            if (IsQuotedPrintableString(input))
            {
                return false;
            }
            else 
            {
                return true;
            }
        }

        private static bool IsQuotedPrintableString(string input)
        {
            // Check if the string is a valid Quoted-Printable encoded string
            string quotedPrintablePattern = @"=\?[^?]+\?Q\?[^?]+\?=";
            return Regex.IsMatch(input, quotedPrintablePattern, RegexOptions.IgnoreCase);
        }
    }
        
/*    class Program
    {
        static void Main()
        {
            string username = "2082656720@qq.com";
            string password = "ovwdfnqxjxceiifi"; // 需要获取的是授权码，不是qq密码

            Pop3 pop3Client = new Pop3(username, password);
            pop3Client.Connect();
            pop3Client.List();
            pop3Client.Open(10);
            // pop3Client.Delete(2);
            pop3Client.Disconnect();
        }
    }*/
}



